#ifndef __MQ_EXCHANGE_HPP__
#define __MQ_EXCHANGE_HPP__

#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <vector>
#include <mutex>
#include "../mqcommon/mq_msg.pb.h"
#include <sstream>
#include "../mqcommon/mq_log.hpp"
#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_proto.pb.h"

namespace mq
{
    // 1.定义交换机类。
    struct Exchange
    {
        using Ptr = std::shared_ptr<Exchange>;
        // 1.交换机名称
        std::string name;
        // 2.交换机类型
        ExchangeType type;
        // 3.交换机持久化标志。
        bool durable;
        // 4.是否自动删除标志。
        bool auto_delete;
        // 5.其它参数
        google::protobuf::Map<std::string, std::string> args;
        Exchange(){}
        Exchange(const std::string& ename,
            ExchangeType etype,
            bool edurable,
            bool eauto_delete,
            google::protobuf::Map<std::string, std::string> eargs
        )
            :name(ename)
            ,type(etype)
            ,durable(edurable)
            ,auto_delete(eauto_delete)
            ,args(eargs.begin(),eargs.end())
        {}
        // 内部解析str_args字符串。
        void setArgs(const std::string& str_args)
        {
            // '&'分隔符。
            // key=val&key=val&
            std::vector<std::string> vct_args;
            Helper::StrHelper::split(str_args,"&",vct_args);
            for(auto& str : vct_args)
            {
                size_t pos = str.find('=');
                std::string key = str.substr(0,pos);
                std::string val = str.substr(pos + 1);
                args[key] = val;
            }
        }
        // 将args中的内容进行序列化后，返回一个字符串。
        std::string getArgs()
        {
            std::string result;
            for(auto start = args.begin();start != args.end();++start)
            {
                result += (start->first + "=" + start->second + "&");
            }

            return result;
        }
    };
    using ExchangeMap = std::unordered_map<std::string,Exchange::Ptr>; 
    // 2.定义交换机数据持久化管理类--数据存储在slite数据库中。
    class ExchangeMapper
    {
    public:
        using Ptr =std::shared_ptr<ExchangeMapper>;
        ExchangeMapper(const std::string& dbfile)
            :_sql_helper(dbfile)
        {
            std::string path = mq::Helper::FileHelper::parentDirctory(dbfile);
            mq::Helper::FileHelper::createDirectory(path);
            mq::Helper::FileHelper::createFile(dbfile);
            assert(_sql_helper.open());
            //_sql_helper.open();
            createTable();
        }
        void createTable()
        {
            // 语句中的命令变量要写清楚，仔细，必须要一致。
            #define CREATE_TABLE "create table if not exists exchange_table\
            (\
            name varchar(32) primary key,\
            type int,\
            durable int,\
            auto_delete int,\
            args varchar(128));"
            bool ret = _sql_helper.exec(CREATE_TABLE,nullptr,nullptr);
            if(ret == false)
            {
                DLOG("创建exchange_table失败!");
                abort();// 异常退出程序。
            }
        }
        void removeTable()
        {
            #define DROP_TABLE "drop table if exists exchange_table;"
            bool ret = _sql_helper.exec(DROP_TABLE,nullptr,nullptr);
            if(ret == false)
            {
                DLOG("删除exchange_table中的元素失败!");
                abort();// 异常退出程序。
            }
        }
        // C++分格
        bool insert(Exchange::Ptr& exp)
        {
            std::stringstream ss;
            ss << "insert into exchange_table values(";
            ss << "'" << exp->name << "'," ;
            ss << exp->type  << ",";
            ss << exp->durable   << ",";
            ss << exp->auto_delete  << ",";
            ss << "'" << exp->getArgs() << "');";

            return _sql_helper.exec(ss.str(),nullptr,nullptr);
        }
        void remove(const std::string& name)
        {
            std::stringstream ss;
            ss << "delete from exchange_table where name=";
            ss << "'" << name << "';";
            _sql_helper.exec(ss.str(),nullptr,nullptr);
        }
        ExchangeMap recovery()
        {
            ExchangeMap result;
            std::string sql = "select name , type , durable , auto_delete ,args from exchange_table;";
            _sql_helper.exec(sql,&ExchangeMapper::selectCallback,&result);
            return result;
        }
    private:
        static int selectCallback(void* arg,int numcol,char** row,char** fields)
        {
            ExchangeMap* result = static_cast<ExchangeMap*>(arg);
            auto exp = std::make_shared<Exchange>();
            exp->name = row[0];
            exp->type = (mq::ExchangeType)std::stoi(row[1]);
            exp->durable = (bool)std::stoi(row[2]);
            exp->auto_delete = (bool)std::stoi(row[3]);
            if(row[4])
            {
                exp->setArgs(row[4]);
            }
            result->insert(std::make_pair(exp->name,exp));

            return 0;
        }
    private:
        mq::Helper::SqliteHelper _sql_helper;
    };
    // 3.定义交换机数据内存管理类。
    class ExchangeManager
    {
    public:
        using Ptr = std::shared_ptr<ExchangeManager>;
        ExchangeManager(const std::string& dbfile)
            :_mapper(dbfile)
        {
            _exchanges = _mapper.recovery();
        }
        // 声明交换机
        bool declareExchange(const std::string& name,
            ExchangeType type,
            bool durable,
            bool auto_delete,
            const google::protobuf::Map<std::string, std::string>& args)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 使用唯一标识来查找交换机。
            std::unordered_map<std::string,Exchange::Ptr>::iterator it = _exchanges.find(name);
            if(it != _exchanges.end())
            {
                DLOG("交换机已存在！");
                return true;
            }
            Exchange::Ptr exp = std::make_shared<Exchange>(name,type,durable,auto_delete,args);
            // 持久化存储。
            if(durable == true)
            {
                bool ret = _mapper.insert(exp);
                if(ret == false)
                {

                    return false;
                }
            }
            _exchanges.insert(std::make_pair(name,exp));

            return true;
        }
        // 删除交换机。
        void deleteExchange(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);

            // std::unordered_map<std::string,Exchange::Ptr>::iterator it = _exchanges.find(name);
            auto it = _exchanges.find(name);
            if(it == _exchanges.end())
            {
                DLOG("交换机%s不存在",name.c_str());

                return ;
            }
            // 久持续状态的。
            if(it->second->durable == true)
            {
                _mapper.remove(name);
            }
            _exchanges.erase(it);
        }
        // 获取指定交换机的对象。
        Exchange::Ptr selectExchange(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            std::unordered_map<std::string,Exchange::Ptr>::iterator it  = _exchanges.find(name);
            if(it == _exchanges.end())
            {
                DLOG("没找到对应的交换机。");

                return nullptr;
            }

            return it->second;
        }
        // 判断交换机是否存在。
        bool exist(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);

            std::unordered_map<std::string,Exchange::Ptr>::iterator it  = _exchanges.find(name);
            if(it == _exchanges.end())
            {

                return false;
            }

            return true;
        }
        // 交换机的数量
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);

            std::cout << _exchanges.size() << std::endl;

            return _exchanges.size();
        }
        // 清除交换机。
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);

            _mapper.removeTable();
            _exchanges.clear();

            return ;
        }
    private:
        std::mutex _mutex;
        ExchangeMapper _mapper;
        std::unordered_map<std::string,Exchange::Ptr> _exchanges;
    };
}

#endif